﻿using System;
using System.Collections.Generic;
using System.Linq;

// ReSharper disable CheckNamespace
namespace Equinoxe.EZNFC.Library
// ReSharper restore CheckNamespace
{
    /// <summary>
    /// Observable reactive collection for Tag
    /// </summary>
    /// <remarks></remarks>
    public class ObservableTagCollection : IObservable<INFCTag>
    {
        /// <summary>
        /// Registered observers
        /// </summary>
        private readonly IList<IObserver<INFCTag>> _registeredobservers = new List<IObserver<INFCTag>>();

        /// <summary>
        /// Subscribes the specified observer.
        /// </summary>
        /// <param name="observer">The observer.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public IDisposable Subscribe(IObserver<INFCTag> observer)
        {
            if (!_registeredobservers.Contains(observer))
                _registeredobservers.Add(observer);

            return new SimpleDisposableClass(_registeredobservers, observer);
        }

        /// <summary>
        /// Push new tag.
        /// </summary>
        /// <param name="message">The new tag.</param>
        /// <remarks></remarks>
        public void NewTag(INFCTag message)
        {
            foreach (var observer in _registeredobservers)
            {
                observer.OnNext(message);
            }
        }

        /// <summary>
        /// Stops this instance.
        /// </summary>
        /// <remarks></remarks>
        public void Stop()
        {
            foreach (var observer in _registeredobservers.ToList())
            {
                observer.OnCompleted();
            }

            _registeredobservers.Clear();
        }

        /// <summary>
        /// Simple disposable class
        /// </summary>
        /// <remarks></remarks>
        private class SimpleDisposableClass : IDisposable
        {
            /// <summary>
            /// Observer list
            /// </summary>
            private readonly IList<IObserver<INFCTag>> _observerlist;
            /// <summary>
            /// This observer
            /// </summary>
            private readonly IObserver<INFCTag> _observer;


            /// <summary>
            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            /// </summary>
            /// <remarks></remarks>
            public void Dispose()
            {
                if ((_observer != null) && (_observerlist.Contains(_observer)))
                    _observerlist.Remove(_observer);
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="SimpleDisposableClass"/> class.
            /// </summary>
            /// <param name="observerlist">The observerlist.</param>
            /// <param name="observer">The observer.</param>
            /// <remarks></remarks>
            public SimpleDisposableClass(IList<IObserver<INFCTag>> observerlist, IObserver<INFCTag> observer)
            {
                _observer = observer;
                _observerlist = observerlist;
            }
        }

    }

    /// <summary>
    /// Tag collection observer
    /// </summary>
    /// <remarks></remarks>
    public class TagCollectionObserver : IObserver<INFCTag>
    {
        /// <summary>
        /// Reference to disposable object
        /// </summary>
        private IDisposable _disposableobject;

        /// <summary>
        /// On next action
        /// </summary>
        private Action<INFCTag> _action_onnext;

        /// <summary>
        /// On exception
        /// </summary>
        private Action<Exception> _action_onexception;

        /// <summary>
        /// On completed
        /// </summary>
        private Action _action_oncompleted;


        /// <summary>
        /// Initializes a new instance of the <see cref="TagCollectionObserver"/> class.
        /// </summary>
        /// <param name="onnext">The onnext.</param>
        /// <param name="onexception">The onexception.</param>
        /// <param name="oncompleted">The oncompleted.</param>
        /// <remarks></remarks>
        public TagCollectionObserver(Action<INFCTag> onnext, Action<Exception> onexception = null, Action oncompleted = null)
        {
            _action_onnext = onnext;

            _action_onexception = onexception;

            _action_oncompleted = oncompleted;
        }


        /// <summary>
        /// Subscribes the specified messageprovider.
        /// </summary>
        /// <param name="messageprovider">The messageprovider.</param>
        /// <remarks></remarks>
        public void Subscribe(IObservable<INFCTag> messageprovider)
        {
            if (messageprovider != null)
                _disposableobject = messageprovider.Subscribe(this);
        }

        /// <summary>
        /// Uns the subscribe.
        /// </summary>
        /// <remarks></remarks>
        public void UnSubscribe()
        {
            if (_disposableobject != null)
                _disposableobject.Dispose();
        }

        /// <summary>
        /// Called when next value pushed.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <remarks></remarks>
        public void OnNext(INFCTag value)
        {
            if (_action_onnext != null)
                _action_onnext(value);
        }

        /// <summary>
        /// Called when an error occurs.
        /// </summary>
        /// <param name="error">The error.</param>
        /// <remarks></remarks>
        public void OnError(Exception error)
        {
            if (_action_onnext != null)
                _action_onexception(error);
        }

        /// <summary>
        /// Called when completed.
        /// </summary>
        /// <remarks></remarks>
        public void OnCompleted()
        {
            if (_action_onnext != null)
                _action_oncompleted();
        }
    }

}
